snapshot: Add gtk_snapshot_from_parent
authorTimm Bäder <tbaeder@redhat.com>
Wed, 16 Jan 2019 07:30:42 +0000 (08:30 +0100)
committerTimm Bäder <mail@baedert.org>
Wed, 16 Jan 2019 18:01:40 +0000 (19:01 +0100)
Most of the time, the GtkSnapshot objects we create while snapshotting
widgets don't end up containing all that many nodes or states in their
respective node or state stack. This undermines the amortized allocation
behavior of the G(Ptr)Array we use for the stacks. So instead, use the
(until now unused) parent_snapshot GtkSnapshot* passed to
gtk_widget_create_render_node and reuse its node and state stack.

We do not avoid allocating a new GtkSnapshot object, but we do avoid
allocating a ton of G(Ptr)Array objects and we also avoid realloc'ing
their storage.

gtk/gtksnapshot.c
gtk/gtksnapshotprivate.h
gtk/gtkwidget.c

index 3bc18cd4e8068ad5b8755ce7a9d2e50d7cdea0cd..7eb12dd33e7754632f5a139163a1399f473c0cb8 100644 (file)
@@ -162,6 +162,7 @@ gtk_snapshot_new (void)
 
   snapshot = g_object_new (GTK_TYPE_SNAPSHOT, NULL);
 
+  snapshot->from_parent = FALSE;
   snapshot->state_stack = g_array_new (FALSE, TRUE, sizeof (GtkSnapshotState));
   g_array_set_clear_func (snapshot->state_stack, (GDestroyNotify)gtk_snapshot_state_clear);
   snapshot->nodes = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_render_node_unref);
@@ -173,6 +174,24 @@ gtk_snapshot_new (void)
   return snapshot;
 }
 
+/* Private. Does the same as _new but does not allocate a NEW
+ * state/node stack. */
+GtkSnapshot *
+gtk_snapshot_new_with_parent (GtkSnapshot *parent_snapshot)
+{
+  GtkSnapshot *snapshot = g_object_new (GTK_TYPE_SNAPSHOT, NULL);
+
+  snapshot->state_stack = parent_snapshot->state_stack;
+  snapshot->nodes = parent_snapshot->nodes;
+  snapshot->from_parent = TRUE;
+
+  gtk_snapshot_push_state (snapshot,
+                           0, 0,
+                           gtk_snapshot_collect_default);
+
+  return snapshot;
+}
+
 /**
  * gtk_snapshot_free_to_node: (skip)
  * @snapshot: (transfer full): a #GtkSnapshot
@@ -904,7 +923,8 @@ gtk_snapshot_pop_internal (GtkSnapshot *snapshot)
   guint state_index;
   GskRenderNode *node;
 
-  if (snapshot->state_stack->len == 0)
+  if (snapshot->state_stack->len == 0 &&
+      !snapshot->from_parent)
     {
       g_warning ("Too many gtk_snapshot_pop() calls.");
       return NULL;
@@ -950,17 +970,21 @@ gtk_snapshot_to_node (GtkSnapshot *snapshot)
   GskRenderNode *result;
 
   /* We should have exactly our initial state */
-  if (snapshot->state_stack->len > 1)
+  if (snapshot->state_stack->len > 1 &&
+      !snapshot->from_parent)
     {
       g_warning ("Too many gtk_snapshot_push() calls. %u states remaining.", snapshot->state_stack->len);
     }
-  
+
   result = gtk_snapshot_pop_internal (snapshot);
 
-  g_array_free (snapshot->state_stack, TRUE);
-  snapshot->state_stack = NULL;
+  if (!snapshot->from_parent)
+    {
+      g_array_free (snapshot->state_stack, TRUE);
+      g_ptr_array_free (snapshot->nodes, TRUE);
+    }
 
-  g_ptr_array_free (snapshot->nodes, TRUE);
+  snapshot->state_stack = NULL;
   snapshot->nodes = NULL;
 
   return result;
index b54fb4b7028e37008021716a9561845b89271875..5e554ca85ec1b5156ac61bc9a172ee80555dff5e 100644 (file)
@@ -90,6 +90,8 @@ struct _GdkSnapshot {
 
   GArray                *state_stack;
   GPtrArray             *nodes;
+
+  guint from_parent : 1;
 };
 
 struct _GtkSnapshotClass {
@@ -99,6 +101,8 @@ struct _GtkSnapshotClass {
 void                    gtk_snapshot_append_node_internal       (GtkSnapshot            *snapshot,
                                                                  GskRenderNode          *node);
 
+GtkSnapshot *           gtk_snapshot_new_with_parent            (GtkSnapshot            *parent_snapshot);
+
 G_END_DECLS
 
 #endif /* __GTK_SNAPSHOT_PRIVATE_H__ */
index 4fadd96534491748fc0f137c656c49b41051263d..7e03bfc987df6e1d70ded180b63a0582b340fc12 100644 (file)
@@ -12961,7 +12961,7 @@ gtk_widget_create_render_node (GtkWidget   *widget,
   if (opacity <= 0.0)
     return NULL;
 
-  snapshot = gtk_snapshot_new ();
+  snapshot = gtk_snapshot_new_with_parent (parent_snapshot);
 
   _gtk_widget_get_allocation (widget, &allocation);
   gtk_snapshot_push_debug (snapshot,